package com.winning.shiro.shiroboot.config;

import com.winning.shiro.shiroboot.realm.SecondShiroRealm;
import com.winning.shiro.shiroboot.realm.ShiroRealm;
import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author Lenovo
 * @title
 * @project shiro-boot
 * @package com.winning.shiro.shiroboot.config
 * @date: 2019-01-21 14:14
 */
@Configuration
public class ShiroConfig {
    /**
     * 注册EhcacheManager
     * @return
     */
    @Bean(name = "shiroEhcacheManager")
    public CacheManager shiroEhcacheManager(){
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return ehCacheManager;
    }

    /**
     * 配置认证器
     * @return
     */
    @Bean
    public Authenticator modularRealmAuthenticator(){
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        // 认证策略设置
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return authenticator;
    }

    /**
     * 配置Realm  ShiroRealm
     * @return
     */
    @Bean
    public Realm initShiroRealm(){
        ShiroRealm realm = new ShiroRealm();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }

    /**
     * 配置Realm  SecondShiroRealm
     * @return
     */
    @Bean
    public Realm initSecondShiroRealm(){
        SecondShiroRealm realm = new SecondShiroRealm();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("SHA1");
        credentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    /**
     * 开启shiro aop注解支持
     * 使用代理方式，所以需要开启代码支持
     *
     * @param securityManager
     * @return
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean(name = "sessionManager")
    public SessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 会话超时时间，单位：毫秒  20m=1200000ms, 30m=1800000ms, 60m=3600000ms
        sessionManager.setGlobalSessionTimeout(1800000);
        sessionManager.setSessionValidationInterval(1200000);
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }
    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置Realms
        Set<Realm> realms = new HashSet<>();
        realms.add(initShiroRealm());
        realms.add(initSecondShiroRealm());
        securityManager.setRealms(realms);
        // 用户授权/认证信息Cache, 采用EhCache 缓存
        securityManager.setCacheManager(shiroEhcacheManager());
        // 配置认证器
        securityManager.setAuthenticator(modularRealmAuthenticator());
        // 配置session manager
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        Map<String, String> filterChainDefinitionManager = new LinkedHashMap<>();
        filterChainDefinitionManager.put("/vue/**", "anon");
        filterChainDefinitionManager.put("/test/**", "anon");
        // druid 数据库监控
        filterChainDefinitionManager.put("/druid/**", "anon");
        // 登出
        filterChainDefinitionManager.put("/shiro/logout", "logout");
        // 登录
        filterChainDefinitionManager.put("/shiro/login","anon");
        // 静态资源不拦login截
        filterChainDefinitionManager.put("/static/**", "anon");
        // 静态资源不拦截
        filterChainDefinitionManager.put("/resources/**", "anon");
        // 静态资源不拦截
        filterChainDefinitionManager.put("/assets/**", "anon");
        // 对所有用户认证
        filterChainDefinitionManager.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);
        shiroFilterFactoryBean.setLoginUrl("/login.jsp");
        shiroFilterFactoryBean.setSuccessUrl("/main.jsp");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized.jsp");
        return shiroFilterFactoryBean;
    }

}
